/*
 * CPU.c
 *
 *  Created on: Mar 8, 2012
 *      Author: Daniel
 */
#include <stdio.h>
#include <stdlib.h>
#include "Simulator.h"
#include <pthread.h>

int main(int argc, char* argv[]) {
	//==Processes==
	Process calc;
	initializeCalculatorProcess(&calc);
	Process producer;
	initializeProducerProcess(&producer);
	Process consumer;
	initializeConsumerProcess(&consumer);
	Process keyboard;
	initializeKeyboardProcess(&keyboard);

	Process *my_processes[4];
	my_processes[0] = &producer;
	my_processes[1] = &consumer;
	my_processes[2] = &calc;
	my_processes[3] = &keyboard;


	//==Shared Memory==
	SharedMemory m;
	m.locked = 0;
	m.memory1 = 0;
	m.memory2 = 0;


	//==Scheduler==
	//ask for user input on scheduler type.
	printf("What Scheduler would you like?\n");
	printf("0 = Round Robin, 1 = Priority, 2 = Lottery\n");
	fflush(stdout);
	int sched;
	scanf("%d", &sched);
	Scheduler s;
	initializeScheduler(&s, sched, my_processes);

	//==System Timer==
	SystemTimer systime;
	int delay;
	printf("Enter a cycle time for the System timer in seconds (suggested = 3): \n");
	fflush(stdout);
	scanf("%d", &delay);
	initializeSystemTimer(&systime, delay); //this is creating a systemtimer thread!

	//==Devices==
	int kbio = 0;
	pthread_t thread1;
	(void) pthread_create(&thread1, NULL, runKeyboard, &kbio);
	int auxio = 0;
	pthread_t thread2;
	(void) pthread_create(&thread2, NULL, runAux, &auxio);

	Process* currentProcess = getCurrent(&s);
	currentProcess->state = 0;
	int pc = 0; //program counter is set to 0
	printf("Simulator Initialized\n");
	printf("Note: 0=running, 1=ready, 2=interrupted, 3=blocked\n");
	printf("Scheduler: Running Process %d next.\n", currentProcess->id);
	printf("Process 1 (Producer)'s state: %d\n", producer.state);
	printf("Process 2 (Consumer)'s state: %d\n", consumer.state);
	printf("Process 3 (Calculator)'s state: %d\n", calc.state);
	printf("Process 4 (Keyboard)'s state: %d\n\n", keyboard.state);
	fflush(stdout);

	while(1) {
		pause(100000);//make results readable
		//handle interrupts
		if(systime.interrupted == 1) {
			currentProcess->state = 2; //current process is interrupted
			currentProcess->next_PC = pc;
			currentProcess = getNext(&s);
			pc = currentProcess->next_PC;
			systime.interrupted = 0;
			printf("System Timer produced an interrupt.\n");
			printf("Scheduler: Running Process %d next.\n", currentProcess->id);
			printf("Process 1 (Producer)'s state: %d\n", producer.state);
			printf("Process 2 (Consumer)'s state: %d\n", consumer.state);
			printf("Process 3 (Calculator)'s state: %d\n", calc.state);
			printf("Process 4 (Keyboard)'s state: %d\n\n", keyboard.state);
			fflush(stdout);
		}
		//handle system calls
		if(pc == currentProcess->request_at ) {//There is a system call on this instruction
			currentProcess->state = 3; //process is now blocked
			while(currentProcess->state == 3) { //while the current process is blocked
				switch(currentProcess->request) {
					case SYS_IO:
						printf("Keyboard made a system call to keyboard device.\n");
						if(kbio == 1) { //if keyboard device input is flagged
							currentProcess->state = 0; //running
							kbio = 0; //reset kbio
						}
						 break;
					case SYS_SEM_DOWN:
						printf("Consumer attempted to decrement memory location 1.\n");
						if(m.memory1 != 0) {
							currentProcess->state = 0; //running
							mem1Down(&m);
						}
						 break;
					case SYS_SEM_UP:
						printf("Producer attempted to increment memory location 1.\n");
						currentProcess->state = 0; //running
						mem1Up(&m);
						break;
					case SYS_MEM_RW:
						printf("Calculator made a system call to AUX Device.\n");
						if(auxio == 1) {
							currentProcess->state = 0; //running
							auxio = 0;
						}
						 break;
					default:
						printf("Default ran, this is bad\n");
						break;
				}
				if(currentProcess->state == 3) {
					printf("Process is still blocked. Moving on.\n");
					currentProcess = getNext(&s);
					pc = currentProcess->next_PC;
					printf("Scheduler: Running Process %d next.\n", currentProcess->id);
					printf("Process 1 (Producer)'s state: %d\n", producer.state);
					printf("Process 2 (Consumer)'s state: %d\n", consumer.state);
					printf("Process 3 (Calculator)'s state: %d\n", calc.state);
					printf("Process 4 (Keyboard)'s state: %d\n\n", keyboard.state);
					fflush(stdout);
				}

			}
		}
		pc++;

		fflush(stdout);
		if(pc == currentProcess->instructions) { //if the processes instructions finish
			printf("Process %d complete, running next process.\n", currentProcess->id);


			currentProcess->next_PC = 0;
			currentProcess->state = 1;
			currentProcess = getNext(&s);
			pc = currentProcess->next_PC;
			currentProcess->state = 0;

			printf("Scheduler: Running Process %d next.\n", currentProcess->id);
			printf("Process 1 (Producer)'s state: %d\n", producer.state);
			printf("Process 2 (Consumer)'s state: %d\n", consumer.state);
			printf("Process 3 (Calculator)'s state: %d\n", calc.state);
			printf("Process 4 (Keyboard)'s state: %d\n\n", keyboard.state);
		}
	}
	return EXIT_SUCCESS;
}
